//
//  NSString+ADUtil.m
//  ADKit
//
//  Created by duzexu on 2017/12/1.
//  Copyright © 2017年 duzexu. All rights reserved.
//

#import "NSString+ADUtil.h"
#import "ADKitHeaders.h"
#import <CommonCrypto/CommonCryptor.h>
#import <Security/Security.h>

static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

@implementation NSString (ADUtil)

- (CGSize)ad_sizeForFont:(UIFont *)font {
    return [self sizeForFont:font size:CGSizeMake(MAXFLOAT, MAXFLOAT) mode:NSLineBreakByWordWrapping];
}

- (NSString*)ad_trim {
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

- (NSString *)ad_removeBothEndsWhitespace {
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}

- (NSString *)ad_trimWhitespace {
    NSMutableString *str = [self mutableCopy];
    CFStringTrimWhitespace((__bridge CFMutableStringRef)str);
    return str;
}

- (NSString *)ad_trimAllWhitespace {
    return [self stringByReplacingOccurrencesOfString:@" " withString:@""];
}

- (BOOL)ad_isVaild {
    if ([[self ad_trim] length] <= 0 || self == (id)[NSNull null]) {
        return NO;
    }
    return YES;
}

- (BOOL)ad_isValidateWithRegex:(NSString *)regex {
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    return [pre evaluateWithObject:self];
}

- (BOOL)ad_isVaildPhone {
    NSString *phoneRegex = @"^1\\d{10}$";
    NSPredicate *phone = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",phoneRegex];
    return [phone evaluateWithObject:self];
}

- (BOOL)ad_isVaildEmail {
    NSString *emailRegex = @"^([a-z0-9A-Z_-])+(\\.[a-z0-9A-Z_-]+)*@([a-z0-9A-Z_-])+((\\.\\w{2,3}){1,3})$";
    NSPredicate *email = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",emailRegex];
    return [email evaluateWithObject:self];
}

- (BOOL)ad_isAllNumbers {
    NSString *numberRegex = @"^[0-9]*$";
    NSPredicate *number = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",numberRegex];
    return [number evaluateWithObject:self];
}

- (BOOL)ad_isAllCharacter {
    NSString *characterRegex = @"^[A-Za-z]+$";
    NSPredicate *character = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",characterRegex];
    return [character evaluateWithObject:self];
}

- (BOOL)ad_isValidCharacterOrNumber {
    // 编写正则表达式：只能是数字或英文，或两者都存在
    NSString *regex = @"^[a-z0－9A-Z]*$";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    return [predicate evaluateWithObject:self];
}

- (BOOL)ad_haveEmoji {
    NSString *emojiRegex = @"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]";
    NSPredicate *emoji = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",emojiRegex];
    return [emoji evaluateWithObject:self];
}

- (BOOL)ad_haveChinese {
    for (int i = 0; i < self.length; i++) {
        unichar ch = [self characterAtIndex:i];
        if (0x4e00 < ch  && ch < 0x9fff) {
            return YES;
        }
    }
    return NO;
}

- (BOOL)ad_isAllChinese {
    for (int i = 0; i < self.length; i++) {
        unichar ch = [self characterAtIndex:i];
        if (0x4e00 > ch  || ch > 0x9fff) {
            return NO;
        }
    }
    return YES;
}

- (BOOL)ad_haveSpecialCharacter {
    BOOL bRet = YES;
    for(int i=0; i< self.length;i++) {
        unichar uChar = [self characterAtIndex:i];
        if( uChar > 0x4e00 && uChar < 0x9fff) {//汉字
            bRet = bRet&1;
        }else if(uChar >=0x30 && uChar <=0x39) {//数字
            bRet = bRet&1;
        }else if(uChar >=0x61 && uChar <=0x7a) {//英文大写 0x61,0x7a
            bRet = bRet&1;
        }else if(uChar >=0x41 && uChar <=0x5a) {
            bRet = bRet&1;
        }else if(uChar ==  0x005f||uChar == 0x002e) {
            bRet = bRet&1;
        }else{
            bRet = bRet&0;
        }
    }
    return bRet;
}

- (BOOL)ad_isVaildIdentityCard {
    //判断是否为空
    if (self.length <= 0) {
        return NO;
    }
    //判断是否是18位，末尾是否是x
    NSString *regex2 = @"^(\\d{14}|\\d{17})(\\d|[xX])$";
    NSPredicate *identityCardPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex2];
    if(![identityCardPredicate evaluateWithObject:self]) {
        return NO;
    }
    //判断生日是否合法
    NSRange range = NSMakeRange(6,8);
    NSString *datestr = [self substringWithRange:range];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat : @"yyyyMMdd"];
    if([formatter dateFromString:datestr]==nil){
        return NO;
    }
    
    //判断校验位
    if(self.length==18)
    {
        NSArray *idCardWi = @[ @"7", @"9", @"10", @"5", @"8", @"4", @"2", @"1", @"6", @"3", @"7", @"9", @"10", @"5", @"8", @"4", @"2" ]; //将前17位加权因子保存在数组里
        NSArray * idCardY = @[ @"1", @"0", @"10", @"9", @"8", @"7", @"6", @"5", @"4", @"3", @"2" ]; //这是除以11后，可能产生的11位余数、验证码，也保存成数组
        int idCardWiSum=0; //用来保存前17位各自乖以加权因子后的总和
        for(int i = 0;i < 17;i++){
            idCardWiSum+=[[self substringWithRange:NSMakeRange(i,1)] intValue]*[idCardWi[i] intValue];
        }
        
        int idCardMod=idCardWiSum%11;//计算出校验码所在数组的位置
        NSString *idCardLast=[self substringWithRange:NSMakeRange(17,1)];//得到最后一位身份证号码
        
        //如果等于2，则说明校验码是10，身份证号码最后一位应该是X
        if(idCardMod==2){
            if([idCardLast isEqualToString:@"X"]||[idCardLast isEqualToString:@"x"]){
                return YES;
            }else{
                return NO;
            }
        }else{
            //用计算出的验证码与最后一位身份证号码匹配，如果一致，说明通过，否则是无效的身份证号码
            if([idCardLast intValue]==[idCardY[idCardMod] intValue]){
                return YES;
            }else{
                return NO;
            }
        }
    }
    return NO;
}

- (BOOL)ad_isValidCarNo {
    NSString *carRegex = @"^[A-Za-z]{1}[A-Za-z_0-9]{5}$";
    NSPredicate *carTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",carRegex];
    return [carTest evaluateWithObject:self];
}

- (BOOL)isValidUrl {
    NSString *regex = @"^((http)|(https))+:[^\\s]+\\.[^\\s]*$";
    return [self ad_isValidateWithRegex:regex];
}

- (BOOL)isValidPostalcode {
    NSString *phoneRegex = @"^[0-8]\\d{5}(?!\\d)$";
    NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",phoneRegex];
    return [phoneTest evaluateWithObject:self];
}

- (BOOL)isValidIP {
    NSString *regex = [NSString stringWithFormat:@"^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    BOOL rc = [pre evaluateWithObject:self];
    
    if (rc) {
        NSArray *componds = [self componentsSeparatedByString:@","];
        
        BOOL v = YES;
        for (NSString *s in componds) {
            if (s.integerValue > 255) {
                v = NO;
                break;
            }
        }
        
        return v;
    }
    
    return NO;
}

- (BOOL)ad_isValidTaxNo {
    NSString *emailRegex = @"[0-9]\\d{13}([0-9]|X)$";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    return [emailTest evaluateWithObject:self];
}

- (NSString *)ad_safeString {
    return self.ad_isVaild ? self : @"";
}

- (NSString *)ad_hostString {
    return [[NSURL URLWithString:self] host];
}

- (NSString *)ad_toMoneyString {
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    NSLocale*current = [[NSLocale alloc]initWithLocaleIdentifier:@"zh_CN"];
    [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    [numberFormatter setLocale:current];
    NSString *formattedNumberString = [numberFormatter stringFromNumber:@(self.doubleValue)];
    return formattedNumberString;
}

- (NSString *)ad_toPinYin {
    NSMutableString *pinyin = [self mutableCopy];
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformMandarinLatin, NO);
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformStripCombiningMarks, NO);
    return pinyin;
}

- (BOOL)ad_isValidWithMinLenth:(NSInteger)minLenth
                      maxLenth:(NSInteger)maxLenth
                containChinese:(BOOL)containChinese
           firstCannotBeDigtal:(BOOL)firstCannotBeDigtal {
    //  [\u4e00-\u9fa5A-Za-z0-9_]{4,20}
    NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
    NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";
    
    NSString *regex = [NSString stringWithFormat:@"%@[%@A-Za-z0-9_]{%d,%d}", first, hanzi, (int)(minLenth-1), (int)(maxLenth-1)];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    return [pre evaluateWithObject:self];
}

- (BOOL)ad_isValidWithMinLenth:(NSInteger)minLenth
                      maxLenth:(NSInteger)maxLenth
                containChinese:(BOOL)containChinese
                 containDigtal:(BOOL)containDigtal
                 containLetter:(BOOL)containLetter
         containOtherCharacter:(NSString *)containOtherCharacter
           firstCannotBeDigtal:(BOOL)firstCannotBeDigtal {
    NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
    NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";
    NSString *lengthRegex = [NSString stringWithFormat:@"(?=^.{%@,%@}$)", @(minLenth), @(maxLenth)];
    NSString *digtalRegex = containDigtal ? @"(?=(.*\\d.*){1})" : @"";
    NSString *letterRegex = containLetter ? @"(?=(.*[a-zA-Z].*){1})" : @"";
    NSString *characterRegex = [NSString stringWithFormat:@"(?:%@[%@A-Za-z0-9%@]+)", first, hanzi, containOtherCharacter ? containOtherCharacter : @""];
    NSString *regex = [NSString stringWithFormat:@"%@%@%@%@", lengthRegex, digtalRegex, letterRegex, characterRegex];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    return [pre evaluateWithObject:self];
}

@end

@implementation NSAttributedString (ADUtil)

- (CGSize)ad_size {
    return [self ad_sizeWithLimitSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];
}

- (CGSize)ad_sizeWithLimitSize:(CGSize)limitSize {
    return [self boundingRectWithSize:limitSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size;
}

- (CGSize)ad_sizeWithLimitWidth:(CGFloat)limitWidth {
    return [self ad_sizeWithLimitSize:CGSizeMake(limitWidth, MAXFLOAT)];
}

@end

@implementation NSString (ADEncrypt)

- (NSString *)ad_DesEncryptWithKey:(NSString *)key {
    NSString *ciphertext = nil;
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = (data.length + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    dataLength = dataLength * sizeof(uint8_t);
    unsigned char buffer[dataLength];
    memset(buffer, 0, sizeof(char));
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding,
                                          [key UTF8String], kCCKeySizeDES,
                                          [key UTF8String],
                                          [data bytes], data.length,
                                          buffer, dataLength,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
        ciphertext = [data base64EncodedString];
    }
    if (cryptStatus == kCCBufferTooSmall) {
        ciphertext = @"";
        NSLog(@"buffer 太短 %zu",numBytesEncrypted);
    }
    return ciphertext;
}

- (NSData *)ad_DesDecryptWithKey:(NSString *)key {
    NSData *data = [NSData dataWithBase64EncodedString:self];
    NSUInteger dataLength = data.length;
    unsigned char buffer[dataLength];
    memset(buffer, 0, sizeof(char));
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding,
                                          [key UTF8String], kCCKeySizeDES,
                                          [key UTF8String],
                                          [data bytes], dataLength,
                                          buffer, dataLength,
                                          &numBytesDecrypted);
    if(cryptStatus == kCCSuccess) {
        NSData *result = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
        return result;
    }
    return nil;
}

@end

@implementation NSString (ADLocalized)

- (NSString *)ad_localized {
    return NSLocalizedString(self, comment: self);
}

@end
